package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Observable;
import java.util.Observer;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.WindowConstants;

import listener.LayeredPaneListener;
import listener.ListListener;
import listener.MenuListener;
import listener.ToolBarListener;
import model.Layer;
import utils.ObserverUtils;
import utils.Parameters;
import abstraction.ToolBarButton;
import controller.MainController;

public class MainFrame extends JFrame implements Observer {

	public enum Action {
		SELECT, MOVE, DRAW, BRUSH, SPRAY, ERASE
	}

	public enum GlassPaneState {
		RESIZE, ROTATE, DEFAULT, CUT
	}

	private static MainFrame m_singleton;
	private JMenuBar m_menuBar;
	private JMenu m_menuFile;
	private JMenu m_menuLayer;
	private JMenu m_menuFilters;
	private JMenuItem m_menuNew;
	private JMenuItem m_menuSave;
	private JMenuItem m_menuQuit;
	private JToolBar m_toolBar;
	private JPanel m_mainPanel;
	private KoalaLayeredPane m_drawingPane;
	private JList m_layerList;
	private JScrollPane m_layerPane;
	private KoalaGlassPane m_defaultGlassPane;
	private ResizeGlassPane m_resizeGlassPane;
	private RotateGlassPane m_rotateGlassPane;
	private CutGlassPane m_cutGlassPane;
	private JScrollPane m_scrollingPane;

	private JTextField m_colorSelected;
	private JSlider m_sizeSlider;
	private JTextField m_sizeSelected;

	private Action m_curAction;

	private DefaultListModel listModel;

	private int m_width;
	private int m_height;
	private int m_count;
	private JMenu m_menuSettings;
	private JMenuItem m_displayGridMenu;
	private ToolBarButton m_selectButton;

	public static MainFrame getInstance() {
		if (m_singleton == null) {
			m_singleton = new MainFrame();
		}

		return m_singleton;
	}

	public MainFrame() {
		super();
		initializeFrame();
		initializeMenu();
		this.setVisible(true);
	}

	public void initializeToolBar() {
		m_toolBar = new JToolBar("Tools");

		// --- Creating items
		ToolBarButton saveButton = new ToolBarButton("save.png");
		// - layer
		ToolBarButton newEmptyLayerButton = new ToolBarButton(
				"add_empty_layer.png");
		ToolBarButton newColorLayerButton = new ToolBarButton(
				"add_color_layer.png");
		ToolBarButton newImageLayerButton = new ToolBarButton(
				"add_img_layer.png");
		ToolBarButton newTextLayerButton = new ToolBarButton(
				"add_text_layer.png");
		ToolBarButton deleteLayerButton = new ToolBarButton("delete_layer.png");
		// - actions
		ToolBarButton moveLayerButton = new ToolBarButton("move_push.png",
				"move.png");
		m_selectButton = new ToolBarButton("select_push.png", "select.png");
		ToolBarButton rotateButton = new ToolBarButton("rotate.png",
				"rotate_push.png");
		ToolBarButton cutButton = new ToolBarButton("cut.png");
		ToolBarButton resizeButton = new ToolBarButton("resize.png");
		ToolBarButton eraseButton = new ToolBarButton("erase_push.png",
				"erase.png");
		ToolBarButton crayonButton = new ToolBarButton("crayon_push.png",
				"crayon.png");
		ToolBarButton brushButton = new ToolBarButton("brush_push.png",
				"brush.png");
		// TODO img du spray push
		ToolBarButton sprayButton = new ToolBarButton("spray.png", "spray.png");
		// - brush chooser
		m_sizeSlider = new JSlider(1, Parameters.MAX_SLIDER_VALUE,
				Parameters.DEFAULT_SLIDER_VALUE);
		m_sizeSlider
				.setPreferredSize(new Dimension(Parameters.SIZE_SLIDER, 20));
		m_sizeSelected = new JTextField("" + Parameters.DEFAULT_SLIDER_VALUE);
		m_sizeSelected.setEditable(false);
		m_sizeSelected.setPreferredSize(new Dimension(
				Parameters.SIZE_COLOR_BUTTON * 2,
				Parameters.SIZE_COLOR_BUTTON * 2));
		// -- color selection
		m_colorSelected = new JTextField();
		m_colorSelected.setEditable(false);
		m_colorSelected.setBackground(Color.WHITE);
		m_colorSelected.setPreferredSize(new Dimension(
				Parameters.SIZE_COLOR_BUTTON * 2,
				Parameters.SIZE_COLOR_BUTTON * 2));
		ToolBarButton whiteButton = new ToolBarButton(Color.WHITE);
		ToolBarButton blackButton = new ToolBarButton(Color.BLACK);
		ToolBarButton redButton = new ToolBarButton(Color.RED);
		ToolBarButton blueButton = new ToolBarButton(Color.BLUE);
		ToolBarButton greenButton = new ToolBarButton(Color.GREEN);
		ToolBarButton orangeButton = new ToolBarButton(Color.ORANGE);

		// ---- giving names
		saveButton.setName("save");
		newEmptyLayerButton.setName("add_empty_layer");
		newColorLayerButton.setName("add_color_layer");
		newImageLayerButton.setName("add_img_layer");
		newTextLayerButton.setName("add_text_layer");
		deleteLayerButton.setName("delete_layer");
		moveLayerButton.setName("move");
		m_selectButton.setName("select");
		resizeButton.setName("resize");
		rotateButton.setName("rotate");
		cutButton.setName("cut");
		eraseButton.setName("erase");
		crayonButton.setName("crayon");
		brushButton.setName("brush");
		sprayButton.setName("spray");
		// --color button
		whiteButton.setName("white");
		blackButton.setName("black");
		redButton.setName("red");
		blueButton.setName("blue");
		greenButton.setName("green");
		orangeButton.setName("orange");
		m_colorSelected.setName("colorSelected");

		// TODO Legende ==> setToolTipText

		// ---- setting listener
		saveButton.addActionListener(new ToolBarListener());
		newEmptyLayerButton.addActionListener(new ToolBarListener());
		newColorLayerButton.addActionListener(new ToolBarListener());
		newImageLayerButton.addActionListener(new ToolBarListener());
		newTextLayerButton.addActionListener(new ToolBarListener());
		deleteLayerButton.addActionListener(new ToolBarListener());
		moveLayerButton.addActionListener(new ToolBarListener());
		m_selectButton.addActionListener(new ToolBarListener());
		resizeButton.addActionListener(new ToolBarListener());
		rotateButton.addActionListener(new ToolBarListener());
		cutButton.addActionListener(new ToolBarListener());
		eraseButton.addActionListener(new ToolBarListener());
		crayonButton.addActionListener(new ToolBarListener());
		brushButton.addActionListener(new ToolBarListener());
		sprayButton.addActionListener(new ToolBarListener());
		whiteButton.addActionListener(new ToolBarListener());
		blackButton.addActionListener(new ToolBarListener());
		redButton.addActionListener(new ToolBarListener());
		blueButton.addActionListener(new ToolBarListener());
		greenButton.addActionListener(new ToolBarListener());
		orangeButton.addActionListener(new ToolBarListener());
		m_colorSelected.addMouseListener(new ToolBarListener());
		m_sizeSlider.addChangeListener(new ToolBarListener());

		// ----- adding on toolbar
		m_toolBar.add(saveButton);
		// - separator
		m_toolBar.addSeparator();
		m_toolBar.add(newEmptyLayerButton);
		m_toolBar.add(newImageLayerButton);
		m_toolBar.add(newColorLayerButton);
		m_toolBar.add(newTextLayerButton);
		m_toolBar.add(deleteLayerButton);
		// - separator
		m_toolBar.addSeparator();
		m_toolBar.add(m_selectButton);
		m_toolBar.add(moveLayerButton);
		m_toolBar.add(eraseButton);
		m_toolBar.add(crayonButton);
		m_toolBar.add(brushButton);
		m_toolBar.add(sprayButton);
		// - separator
		m_toolBar.addSeparator();
		m_toolBar.add(resizeButton);
		m_toolBar.add(rotateButton);
		m_toolBar.add(cutButton);
		// - separator
		m_toolBar.addSeparator();
		m_toolBar.add(m_colorSelected);
		m_toolBar.add(whiteButton);
		m_toolBar.add(blackButton);
		m_toolBar.add(redButton);
		m_toolBar.add(blueButton);
		m_toolBar.add(greenButton);
		m_toolBar.add(orangeButton);
		m_toolBar.add(m_sizeSlider);
		m_toolBar.add(m_sizeSelected);

		// -- init value
		m_selectButton.setActive();
		m_curAction = Action.SELECT;

		m_toolBar.setBackground(Color.LIGHT_GRAY);
		this.getContentPane().add(m_toolBar, BorderLayout.SOUTH);
		m_toolBar.setVisible(true);
	}

	public void initializeMenu() {
		m_menuBar = new JMenuBar();

		// -- File
		m_menuFile = new JMenu("File");
		m_menuNew = new JMenuItem("New");
		m_menuSave = new JMenuItem("Save as...");
		m_menuQuit = new JMenuItem("Quit");

		// -- Layer
		m_menuLayer = new JMenu("Layers");
		JMenuItem newSimpleLayer = new JMenuItem("New transparent layer");
		JMenuItem newImgLayer = new JMenuItem("New image layer");
		JMenuItem newTextLayer = new JMenuItem("New text layer");
		JMenuItem newColorLayer = new JMenuItem("New colored layer");
		JMenuItem changeOpacityLayer = new JMenuItem("Change opacity");

		// -- Filters
		m_menuFilters = new JMenu("Filters");
		JMenuItem brightnessContrastFilter = new JMenuItem(
				"Brightness / Contrast");
		JMenuItem pixelFilter = new JMenuItem("Pixel operations");
		JMenuItem colorFilter = new JMenuItem("Color operations");

		// --Settings
		m_menuSettings = new JMenu("Settings");
		m_displayGridMenu = new JMenuItem("Show grid");
		JMenuItem parametersItem = new JMenuItem("Parameters");

		/** Set the name **/
		// -- file
		m_menuNew.setName("new");
		m_menuSave.setName("save");
		m_menuQuit.setName("quit");
		// -- layer
		newSimpleLayer.setName("simple_layer");
		newImgLayer.setName("image_layer");
		newTextLayer.setName("text_layer");
		newColorLayer.setName("color_layer");
		changeOpacityLayer.setName("change_opacity");
		// --filters
		brightnessContrastFilter.setName("brightness_contrast_filter");
		pixelFilter.setName("pixel_filter");
		colorFilter.setName("color_filter");
		// -- settings
		m_displayGridMenu.setName("display_grid");
		parametersItem.setName("parameters");

		/** Set Shortcut **/
		m_menuSave.setMnemonic(KeyEvent.VK_S);
		m_menuNew.setMnemonic(KeyEvent.VK_N);
		m_menuQuit.setMnemonic(KeyEvent.VK_Q);

		/** Adding action to item **/
		// -- file
		m_menuNew.addActionListener(new MenuListener());
		m_menuSave.addActionListener(new MenuListener());
		m_menuQuit.addActionListener(new MenuListener());
		// -- layer
		newSimpleLayer.addActionListener(new MenuListener());
		newImgLayer.addActionListener(new MenuListener());
		newTextLayer.addActionListener(new MenuListener());
		newColorLayer.addActionListener(new MenuListener());
		changeOpacityLayer.addActionListener(new MenuListener());
		// --filters
		brightnessContrastFilter.addActionListener(new MenuListener());
		pixelFilter.addActionListener(new MenuListener());
		colorFilter.addActionListener(new MenuListener());
		m_displayGridMenu.addActionListener(new MenuListener());
		parametersItem.addActionListener(new MenuListener());

		/** Adding item to menu **/
		// -- file
		m_menuFile.add(m_menuNew);
		m_menuFile.add(m_menuSave);
		m_menuFile.addSeparator();
		m_menuFile.add(m_menuQuit);
		// -- layer
		m_menuLayer.add(newSimpleLayer);
		m_menuLayer.add(newImgLayer);
		m_menuLayer.add(newTextLayer);
		m_menuLayer.add(newColorLayer);
		m_menuLayer.addSeparator();
		m_menuLayer.add(changeOpacityLayer);
		// -- filters;
		m_menuFilters.add(brightnessContrastFilter);
		m_menuFilters.add(pixelFilter);
		m_menuFilters.add(colorFilter);
		// -- settings
		m_menuSettings.add(m_displayGridMenu);
		m_menuSettings.addSeparator();
		m_menuSettings.add(parametersItem);
		

		// adding to contentPane
		m_menuBar.add(m_menuFile);
		m_menuBar.add(m_menuLayer);
		m_menuBar.add(m_menuFilters);
		m_menuBar.add(m_menuSettings);

		m_menuFilters.setEnabled(false);
		m_menuSave.setEnabled(false);
		m_menuLayer.setEnabled(false);
		m_displayGridMenu.setEnabled(false);
		this.getContentPane().add(m_menuBar, BorderLayout.NORTH);
		m_menuBar.setVisible(true);
	}

	/**
	 * Initialize parameters of the JFrame
	 */
	public void initializeFrame() {
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				MainController.closeApplication();
			}
		});
		this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		this.setSize(Parameters.WIDTH, Parameters.HEIGHT);
		this.setTitle("KoalaPhoto");
		this.getContentPane().setLayout(new BorderLayout());
		this.setBackground(Color.GRAY);
	}

	public void createNewFile(String title, int width, int height,
			Color bgColor, int alpha) {
		try {
			this.getContentPane().remove(m_mainPanel);
			this.getContentPane().remove(m_layerPane);
			this.getContentPane().remove(m_toolBar);
			this.getContentPane().remove(m_scrollingPane);

		} catch (NullPointerException e) {

		}
		Dimension currentSize = this.getSize();
		m_width = width;
		m_height = height;
		m_mainPanel = new JPanel();

		m_drawingPane = new KoalaLayeredPane(width, height, title, bgColor,
				alpha);
		LayeredPaneListener listener = new LayeredPaneListener();
		m_drawingPane.addMouseListener(listener);
		m_drawingPane.setBackground(Color.YELLOW);
		m_drawingPane.addMouseMotionListener(listener);
		m_drawingPane.setBorder(BorderFactory.createCompoundBorder(
				BorderFactory.createLineBorder(Color.BLACK),
				BorderFactory.createLineBorder(Color.GRAY)));
		m_mainPanel.add(m_drawingPane);
		m_mainPanel.setBorder(BorderFactory.createTitledBorder(title));

		m_scrollingPane = new JScrollPane();
		m_mainPanel.setPreferredSize(new Dimension(m_width, m_height));
		m_scrollingPane.setViewportView(m_mainPanel);
		this.getContentPane().add(m_scrollingPane);

		m_drawingPane.setVisible(true);
		m_mainPanel.setVisible(true);
		this.setSize(currentSize);

		// -- when all is loaded --//
		m_menuSave.setEnabled(true);
		m_menuLayer.setEnabled(true);
		m_menuFilters.setEnabled(true);
		initializeLayerList();
		initializeToolBar();

		// -- init glasspane
		m_rotateGlassPane = new RotateGlassPane();
		m_resizeGlassPane = new ResizeGlassPane();
		m_cutGlassPane = new CutGlassPane();
		m_defaultGlassPane = new KoalaGlassPane();

		setGlassPane(m_defaultGlassPane);

		m_defaultGlassPane.setOpaque(false);
		m_defaultGlassPane.setVisible(true);
		m_rotateGlassPane.setVisible(false);
		m_rotateGlassPane.setOpaque(false);
		m_resizeGlassPane.setVisible(false);
		m_resizeGlassPane.setOpaque(false);
		m_cutGlassPane.setVisible(false);
		m_cutGlassPane.setOpaque(false);

		m_drawingPane.setSelectedLayer((Layer) m_drawingPane.getList()
				.getElementAt(0));
		m_displayGridMenu.setEnabled(true);
		// this.pack();
	}

	public void setGlassPane(GlassPaneState state) {
		switch (state) {
		case RESIZE:
			setGlassPane(m_resizeGlassPane);
			break;
		case ROTATE:
			setGlassPane(m_rotateGlassPane);
			m_rotateGlassPane.getSliderRotation().setValue(0);
			break;
		case DEFAULT:
			setGlassPane(m_defaultGlassPane);
			break;
		case CUT:
			setGlassPane(m_cutGlassPane);
			break;
		}
	}

	public void initializeLayerList() {
		m_layerList = new JList(m_drawingPane.getList());
		m_layerList.addMouseListener(new ListListener());
		m_layerList.addMouseMotionListener(new ListListener());
		m_layerList.setCellRenderer(new LayerListCellRenderer());
		m_layerPane = new JScrollPane(m_layerList);
		this.getContentPane().add(m_layerPane, BorderLayout.EAST);
		m_layerPane.setVisible(true);
	}

	public void setInactiveAll() {
		Component comp[] = m_toolBar.getComponents();

		for (Component component : comp) {
			if (component instanceof ToolBarButton) {
				ToolBarButton button = (ToolBarButton) component;
				button.setInactive();
				repaint();
			}
		}
	}

	@Override
	public void update(Observable o, Object arg) {
		System.out.println("I was notified by " + o.toString() + " with "
				+ arg.toString());

		switch ((ObserverUtils.Action) arg) {
		default:

			break;
		}
	}

	// --- Getters & Setters --- //

	public KoalaLayeredPane getDrawingPane() {
		return m_drawingPane;
	}

	public int getDocumentWidth() {
		return m_width;
	}

	public void setDocumentWidth(int m_width) {
		this.m_width = m_width;
	}

	public int getDocumentHeight() {
		return m_height;
	}

	public void setDocumentHeight(int m_height) {
		this.m_height = m_height;
	}

	public int getCount() {
		return m_count++;
	}

	public Action getCurrentAction() {
		return m_curAction;
	}

	public void setCurrentAction(Action action) {
		m_curAction = action;

		Toolkit tk = Toolkit.getDefaultToolkit();
		Image imgC;
		Cursor monCurseur;

		switch (action) {
		case SELECT:
			MainFrame.getInstance().setCursor(
					Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			break;
		case BRUSH:
			imgC = tk.createImage(this.getClass().getResource(
					"/images/" + "brush.png"));
			monCurseur = tk.createCustomCursor(imgC, new Point(3, 30), "BRUSH");
			MainFrame.getInstance().setCursor(monCurseur);
			break;
		case DRAW:
			imgC = tk.createImage(this.getClass().getResource(
					"/images/" + "crayon.png"));
			monCurseur = tk.createCustomCursor(imgC, new Point(3, 30), "DRAW");
			MainFrame.getInstance().setCursor(monCurseur);
			break;
		case ERASE:
			imgC = tk.createImage(this.getClass().getResource(
					"/images/" + "erase.png"));
			monCurseur = tk
					.createCustomCursor(imgC, new Point(10, 22), "ERASE");
			MainFrame.getInstance().setCursor(monCurseur);
			break;
		case MOVE:
			MainFrame.getInstance().setCursor(
					Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
			break;
		case SPRAY:
			imgC = tk.createImage(this.getClass().getResource(
					"/images/" + "spray.png"));
			monCurseur = tk.createCustomCursor(imgC, new Point(15, 0), "SPRAY");
			MainFrame.getInstance().setCursor(monCurseur);
			break;
		default:
			break;
		}
	}

	public JPanel getMainPanel() {
		return m_mainPanel;
	}

	public JList getLayerList() {
		return m_layerList;
	}

	public JToolBar getToolBar() {
		return m_toolBar;
	}

	public JScrollPane getScrollingPane() {
		return m_scrollingPane;
	}

	public void setColorSelected(Color color) {
		m_colorSelected.setBackground(color);
	}

	public Color getColorSelected() {
		return m_colorSelected.getBackground();
	}

	public void setSizeSelected(int size) {
		m_sizeSelected.setText("" + size);
	}

	public int getSizeSelected() {
		return m_sizeSlider.getValue();
	}

	public ToolBarButton getSelectButton() {
		return m_selectButton;
	}

	public void setSelectButton(ToolBarButton selectButton) {
		this.m_selectButton = selectButton;
	}
}
